package cn.ibizlab.util.web;

import cn.ibizlab.util.filter.SearchContextBase;
import cn.ibizlab.util.domain.DTOBase;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.QueryMapEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.support.PageableSpringQueryMapEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.util.*;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class SearchContextHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

	@Bean
	@ConditionalOnMissingBean
	public QueryMapEncoder feignQueryMapEncoderPageable() {
		return new SearchContexSpringQueryMapEncoder();
	}

	public class SearchContexSpringQueryMapEncoder extends PageableSpringQueryMapEncoder {

		@Override
		public Map<String, Object> encode(Object object) {
			if (supports(object)) {
				try {
					return objectMapper.readValue(objectMapper.writeValueAsString(object), HashMap.class);
				} catch (JsonProcessingException e) {

				}
			}
			return super.encode(object);
		}


		@Override
		protected boolean supports(Object object) {
			return object!=null && ( object instanceof SearchContextBase || object instanceof DTOBase);
		}

	}
	@Value("${ibiz.pageLimit:1000}")
	private int pageLimit=1000;

    private static ObjectMapper objectMapper=new ObjectMapper();

	static {
			objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
	}

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return SearchContextBase.class.isAssignableFrom(parameter.getParameterType()) || DTOBase.class.isAssignableFrom(parameter.getParameterType());
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
								  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		Map<String, String[]> params = webRequest.getParameterMap();
		LinkedHashMap<String,Object> set = new LinkedHashMap<>();
		for (String key : params.keySet()) {
			set.put(key,params.get(key)[0]);
		}
		if(SearchContextBase.class.isAssignableFrom(parameter.getParameterType()) && (!set.containsKey("size"))){
			set.put("size", pageLimit);
		}
		String json = objectMapper.writeValueAsString(set);
		return objectMapper.readValue(json, parameter.getParameterType());
	}
}